﻿using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using DotNet.Utilities.ConsoleHelper;
using PropertyChanged;
using WPFTemplate;
using WPFTemplate.ViewModels;
using WPFTemplateLib.UserControls;
using WPFTemplateLib.WpfHelpers;

namespace DLGCY.FilesWatcher.ViewModels
{
    [AddINotifyPropertyChangedInterface]
    public class MainWindowViewModel : BindableBase
    {
        #region Bindable

        private ConfigItems _configs;
        public ConfigItems Configs
        {
            get
            {
                if (_configs == null)
                {
                    LoadConfigCommand.Execute(false);
                }

                return _configs;
            }

            set => _configs = value;
        }

        private string _Info = "";
        /// <summary>
        /// 信息窗内容;
        /// </summary>
        public string Info
        {
            get => _Info;

            set
            {
                //保证 选择不自动滚动消息 的效果（通过不通知界面实现）,不这样的话新消息来的时候，光标/滚动条 会跳到最上面.

                if (Configs.IsAutoScroll)
                {
                    SetProperty(ref _Info, value);
                }
                else
                {
                    _Info = value;
                }
            }
        }

        /// <summary>
        /// 底部状态栏信息
        /// </summary>
        public string Status { get; set; } = "";

        /// <summary>
        /// 弹窗VM;
        /// </summary>
        public ConfirmBoxViewModel DialogVm { get; set; } = new ConfirmBoxViewModel();

        /// <summary>
        /// 是否正在监控
        /// </summary>
        public bool IsMonitoring { get; set; }

        #endregion

        public MainWindowViewModel()
        {
            Console.SetOut(new ConsoleWriter(ShowInfo));

            SetCommandMethod();

            ShowInfo(@"
            说明：
            1、文件更改可能会产生两条信息；
            2、子文件夹内出现创建删除会产生该文件夹的更改消息；");
        }

        ~MainWindowViewModel()
        {
            _FileSystemWatcher.EnableRaisingEvents = false;
        }

        #region Command

        /// <summary>
        /// 保存配置命令
        /// </summary>
        public ICommand SaveConfigCommand { get; set; }

        /// <summary>
        /// 载入配置命令
        /// </summary>
        public ICommand LoadConfigCommand { get; set; }

        /// <summary>
        /// 清空消息命令
        /// </summary>
        public ICommand ClearInfoCommand { get; set; }

        /// <summary>
        /// 关于弹窗命令
        /// </summary>
        public ICommand AboutCommand { get; set; }

        /// <summary>
        /// 弹窗演示命令
        /// </summary>
        public ICommand DialogCommand { get; set; }

        /// <summary>
        /// 双列信息弹窗演示命令
        /// </summary>
        public ICommand TwoColumnInfoCommand { get; set; }

        /// <summary>
        /// 单列信息弹窗演示命令
        /// </summary>
        public ICommand OneColumnInfoCommand { get; set; }

        /// <summary>
        /// 输入信息弹窗演示命令
        /// </summary>
        public ICommand InputInfoCommand { get; set; }

        /// <summary>
        /// 等待弹框演示命令
        /// </summary>
        public ICommand WaitCommand { get; set; }

        /// <summary>
        /// 选择文件夹命令
        /// </summary>
        public ICommand ChooseFolderCommand { get; set; }

        /// <summary>
        /// 开始监控命令
        /// </summary>
        public ICommand StartWatchCommand { get; set; }

        /// <summary>
        /// 停止监控命令
        /// </summary>
        public ICommand StopWatchCommand { get; set; }

        #endregion

        /// <summary>
        /// 命令方法赋值(在构造函数中调用)
        /// </summary>
        private void SetCommandMethod()
        {
            SaveConfigCommand ??= new RelayCommand(o => true, async o =>
            {
                if (ConfigManager.SaveConfig(Configs))
                {
                    await ConfirmBoxHelper.ShowMessage(DialogVm, "保存配置成功");
                }
                else
                {
                    await ConfirmBoxHelper.ShowMessage(DialogVm, "保存配置失败");
                }
            });

            LoadConfigCommand ??= new RelayCommand(o => true, async o =>
            {
                if (ConfigManager.LoadConfig<ConfigItems>(ref _configs))
                {
                    if (o as bool? != false)
                    {
                        await ConfirmBoxHelper.ShowMessage(DialogVm, "载入配置成功");
                    }
                }
                else
                {
                    await ConfirmBoxHelper.ShowMessage(DialogVm, "载入配置失败");
                }
            });

            ClearInfoCommand ??= new RelayCommand(o => true, o =>
            {
                Info = "";
            });

            AboutCommand ??= new RelayCommand(o => true, o =>
            {
                new AboutWindow().ShowDialog();
            });

            DialogCommand ??= new RelayCommand(o => true, async o =>
            {
                await ConfirmBoxHelper.ShowMessage(DialogVm, "操作前通知", 6);

                await ConfirmBoxHelper.ShowConfirm(DialogVm, "您确定要进行此操作吗？", async () =>
                {
                    #region 业务方法

                    ShowInfo("开始业务操作...");

                    await Task.Delay(1000 * 3);

                    ShowInfo("完成业务操作.");

                    #endregion

                }, ShowInfo);

                await ConfirmBoxHelper.ShowMessage(DialogVm, "操作后通知");
            });

            TwoColumnInfoCommand ??= new RelayCommand(o => true, async o =>
            {
                int leftNameWidth = 50;
                int rightNameWidth = 120;

                DialogVm.CustomContent = new UC_CustomInfo()
                {
                    DataContext = new CustomInfoViewModel()
                    {
                        TitleLeft = "个人信息",
                        TitleRight = "信用额度",
                        TextBottom = "确认继续操作吗？",

                        LeftContent = new StackPanel
                        {
                            Children =
                            {
                                GetControl.GetLineInfo("姓名:", "无名氏", Colors.Red, leftNameWidth),
                                GetControl.GetLineInfo("卡号:", "A001", Colors.Red, leftNameWidth),
                                GetControl.GetLineInfo("业务:", "消费", Colors.Red, leftNameWidth),
                                GetControl.GetLineInfo("借款:", "$100", Colors.Red, leftNameWidth)
                            }
                        },

                        RightContent = new StackPanel
                        {
                            Children =
                            {
                                GetControl.GetLineInfo("总信用额度:", "$1000", Colors.Red, rightNameWidth),
                                GetControl.GetLineInfo("已借款金额:", "$100", Colors.Red, rightNameWidth),
                                GetControl.GetLineInfo("剩余额度:", "$900", Colors.Red, rightNameWidth),
                            }
                        },
                    }
                };

                await ConfirmBoxHelper.ShowConfirm(DialogVm, "", async () =>
                {

                }, ShowInfo, isShowText: false);
            });

            OneColumnInfoCommand ??= new RelayCommand(o => true, async o =>
            {
                int leftNameWidth = 50;

                DialogVm.CustomContent = new UC_CustomInfo()
                {
                    DataContext = new CustomInfoViewModel()
                    {
                        IsOnlyOneColumn = true,
                        TitleLeft = "标题",
                        //IsShowTitle = false,
                        //IsShowBottom = false,

                        LeftContent = new StackPanel
                        {
                            Children =
                            {
                                GetControl.GetLineInfo("姓名:", "无名氏", Colors.Red, leftNameWidth),
                                GetControl.GetLineInfo("卡号:", "A001", Colors.Red, leftNameWidth),
                                GetControl.GetLineInfo("业务:", "消费", Colors.Red, leftNameWidth),
                                GetControl.GetLineInfo("借款:", "$100", Colors.Red, leftNameWidth)
                            }
                        },
                    }
                };

                await ConfirmBoxHelper.ShowConfirm(DialogVm, "", async () =>
                {
                    Console.WriteLine("用户已确认");
                }, ShowInfo, isShowText: false);
            });

            InputInfoCommand ??= new RelayCommand(o => true, async o =>
            {
                var inputVM = new TestInputViewModel()
                {
                    IsOnlyOneColumn = true,
                    TitleLeft = "修改后请点击确定按钮",
                    //IsShowTitle = false,
                    IsShowBottom = false,
                };

                inputVM.LeftContent = new StackPanel
                {
                    Children =
                    {
                        GetControl.GetLineInput("宽度：", nameof(inputVM.InputHeight)),
                        GetControl.GetLineInput("高度：", nameof(inputVM.InputWidth)),
                        GetControl.GetLineInput("编号：", nameof(inputVM.InputNo)),
                    },
                };

                DialogVm.CustomContent = new UC_CustomInfo()
                {
                    DataContext = inputVM,
                };

                await ConfirmBoxHelper.ShowConfirm(DialogVm, "", async () =>
                {
                    Console.WriteLine($"宽度-{inputVM.InputWidth},高度-{inputVM.InputHeight},编号-{inputVM.InputNo}");
                }, ShowInfo, isShowText: false);
            });

            WaitCommand ??= new RelayCommand(o => true, async o =>
            {
                await ConfirmBoxHelper.ShowWait(DialogVm, "正在执行业务操作...", async () =>
                {
                    await Task.Delay(1000 * 10);
                    Console.WriteLine("操作完成");
                });
            });

            ChooseFolderCommand ??= new RelayCommand(o => true, o =>
            {
                System.Windows.Forms.FolderBrowserDialog chooseFolderDialog = new System.Windows.Forms.FolderBrowserDialog();
                if (chooseFolderDialog.ShowDialog() == DialogResult.OK)
                {
                    Configs.FolderPath = chooseFolderDialog.SelectedPath;
                }
            });

            StartWatchCommand ??= new RelayCommand(o => !string.IsNullOrWhiteSpace(Configs.FolderPath), o =>
            {
                IsMonitoring = true;
                MonitorDirectory(Configs.FolderPath, Configs.IsMonitorSubDir);
            });

            StopWatchCommand ??= new RelayCommand(o => true, async o =>
            {
                _FileSystemWatcher.EnableRaisingEvents = false;
                IsMonitoring = false;
                await ConfirmBoxHelper.ShowMessage(DialogVm, $"已停止监控：[{Configs.FolderPath}]");
            });
        }

        #region 辅助方法

        private void ShowInfo(string info)
        {
            if (Info.Length > Configs.AutoHalveThresholdValue && Configs.IsAutoHalve)
            {
                Info = "(已删除一半信息)\r\n" + Info.Remove(0, Configs.AutoHalveThresholdValue / 2);
            }

            Info += $"[{DateTime.Now:HH:mm:ss.ffff}] {info}\r\n\r\n";
        }

        #endregion

        #region 文件夹监控

        private FileSystemWatcher _FileSystemWatcher = new FileSystemWatcher();

        //参考：https://www.infoworld.com/article/3185447/how-to-work-with-filesystemwatcher-in-c.html

        /// <summary>
        /// 开始监控目录
        /// </summary>
        /// <param name="path">目录路径</param>
        /// <param name="isIncludeSubDir">是否包括子目录</param>
        private async void MonitorDirectory(string path, bool isIncludeSubDir = true)
        {
            _FileSystemWatcher.EnableRaisingEvents = false;
            _FileSystemWatcher = new FileSystemWatcher();
            _FileSystemWatcher.Path = path;
            _FileSystemWatcher.IncludeSubdirectories = isIncludeSubDir;

            _FileSystemWatcher.Created += FileSystemWatcher_Created;
            _FileSystemWatcher.Renamed += FileSystemWatcher_Renamed;
            _FileSystemWatcher.Deleted += FileSystemWatcher_Deleted;
            _FileSystemWatcher.Changed += FileSystemWatcher_Changed;

            //开始监控
            _FileSystemWatcher.EnableRaisingEvents = true;

            await ConfirmBoxHelper.ShowMessage(DialogVm, $"已开启监控：[{Configs.FolderPath}]");
        }

        private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"【{GetPathType(e.FullPath)}更改】{GetPath(e)}");
        }

        private void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"【{GetPathType(e.FullPath)}创建】{GetPath(e)}");
        }

        private void FileSystemWatcher_Renamed(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"【{GetPathType(e.FullPath)}重命名】{GetOldPath((RenamedEventArgs)e)} --> {GetPath(e)}");
        }

        private void FileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"【删除】{GetPath(e)}");
        }

        /// <summary>
        /// 获取变动的路径的显示字符串
        /// </summary>
        private string GetPath(FileSystemEventArgs e)
        {
            if (Configs.IsShowFullPath)
            {
                return e.FullPath;
            }

            return e.Name;
        }

        /// <summary>
        /// 获取原先路径的显示字符串
        /// </summary>
        private string GetOldPath(RenamedEventArgs e)
        {
            if (Configs.IsShowFullPath)
            {
                return e.OldFullPath;
            }

            return e.OldName;
        }

        #endregion

        #region 判断是文件还是文件夹

        /// <summary>
        /// 获取路径类型（判断是文件还是文件夹）
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns>PathTypeEnum</returns>
        public static PathTypeEnum GetPathType(string path)
        {
            if (File.Exists(path))
            {
                return PathTypeEnum.文件;
            }
            else if (Directory.Exists(path))
            {
                return PathTypeEnum.文件夹;
            }
            else
            {
                return PathTypeEnum.不存在;
            }
        }

        /// <summary>
        /// 路径类型枚举
        /// </summary>
        public enum PathTypeEnum
        {
            文件, 文件夹, 不存在
        }

        #endregion
    }
}
